package com.iwdnb.gkgz.common.utils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Lists;
import com.iwdnb.bmnf.common.utils.BeanConvertUtils;
import com.iwdnb.gkgz.common.model.dto.prediction.StockPredictionParam;
import com.iwdnb.gkgz.common.model.dto.prediction.StockPredictionStatistics;
import com.iwdnb.gkgz.common.model.dto.StockDayData;
import com.iwdnb.gkgz.common.model.dto.prediction.StockIncomePrediction;
import com.iwdnb.gkgz.common.model.dto.StockMinuteData;
import com.iwdnb.gkgz.common.model.dto.StockPredictionCheckInfo;
import com.iwdnb.gkgz.common.model.dto.StockPredictionData;
import com.iwdnb.gkgz.common.prediction.DefaultPredictionStrategy;
import com.iwdnb.gkgz.common.prediction.PredictionStrategy;
import com.iwdnb.gkgz.common.prediction.PredictionStrategyFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

@Slf4j
public class StockPredictionUtils {

    /**
     * 预测股票的当日价格
     *
     * @param stockDayData
     * @param yesterdayData
     * @param correctDays
     * @param param
     * @return
     */
    public static StockPredictionData doPredictionStock(StockDayData stockDayData,
        StockDayData yesterdayData, List<String> correctDays,
        StockPredictionParam param) {
        if (correctDays.contains(stockDayData)) {
            StockPredictionData stockPredictionData = new StockPredictionData();
            //TODO
            return stockPredictionData;
        }
        PredictionStrategy predictionStrategy = PredictionStrategyFactory.getStrategy(param.getStrategyName());
        StockPredictionData predictionData = predictionStrategy.predictionStock(stockDayData, yesterdayData, param);
        //PredictionStrategy predictionHelper2 = new ThirdPredictionStrategy();
        //StockPredictionData predictionData2 = predictionHelper2.predictionStock(stockDayData);
        //predictionData.setMaxPrice(predictionData.getMaxPrice()
        //    .add(predictionData2.getMaxPrice())
        //    .divide(new BigDecimal(2))
        //    .setScale(2,RoundingMode.HALF_DOWN));
        //predictionData.setMinPrice(predictionData.getMinPrice()
        //    .add(predictionData2.getMinPrice())
        //    .divide(new BigDecimal(2))
        //    .setScale(2,RoundingMode.HALF_UP));
        return predictionData;
    }

    public static StockPredictionCheckInfo checkPrediction(StockPredictionData predictionData,
        StockDayData stockDayData) {
        StockPredictionCheckInfo checkInfo = new StockPredictionCheckInfo();
        boolean matchSell = predictionData.getMaxPrice().compareTo(stockDayData.getMaxPrice()) <= 0;
        checkInfo.setMatchSell(matchSell);
        boolean eqSell = predictionData.getMaxPrice().compareTo(stockDayData.getMaxPrice()) == 0;
        checkInfo.setEqSell(eqSell);
        boolean matchBuy = predictionData.getMinPrice().compareTo(stockDayData.getMinPrice()) >= 0;
        checkInfo.setMatchBuy(matchBuy);
        boolean eqBuy = predictionData.getMinPrice().compareTo(stockDayData.getMinPrice()) == 0;
        checkInfo.setEqBuy(eqBuy);
        checkInfo.setMatchAll(matchSell && matchBuy);
        checkInfo.setEqAll(eqSell && eqBuy);
        return checkInfo;
    }



    /**
     * 获取股票的预测数据
     *
     * @param code
     * @param year
     * @return
     */
    public static List<StockDayData> predictionStock(String code, String year) {
        List<StockDayData> stockDayDataList = StockUtils.getHistoryDataByYear(code, year);
        return predictionStock(stockDayDataList);
    }

    public static List<StockDayData> predictionStock(List<StockDayData> stockDayDataList) {
        return predictionStock(stockDayDataList, getDefaultPredictionParam());
    }

    /**
     * 获取股票的预测数据
     *
     * @param stockDayDataList
     * @return
     */
    public static List<StockDayData> predictionStock(List<StockDayData> stockDayDataList, StockPredictionParam param) {
        if (CollectionUtils.isEmpty(stockDayDataList)) {
            return null;
        }

        StockPredictionData predictionData = new StockPredictionData();
        predictionData.setMaxPrice(stockDayDataList.get(0).getMaxPrice());
        predictionData.setMinPrice(stockDayDataList.get(0).getMinPrice());
        StockPredictionCheckInfo checkInfo = null;
        List<String> correctDays = Lists.newArrayList();
        String code = stockDayDataList.get(0).getCode();
        StockDayData yesterdayData = stockDayDataList.get(0);
        for (StockDayData stockDayData : stockDayDataList) {
            stockDayData.setTodayPrediction(BeanConvertUtils.convert(predictionData, StockPredictionData.class));
            checkInfo = checkPrediction(predictionData, stockDayData);
            stockDayData.setCheckInfo(checkInfo);
            predictionData = doPredictionStock(stockDayData, yesterdayData, correctDays, param);
            stockDayData.setTomorrowPrediction(predictionData);
            yesterdayData = stockDayData;
            //log.info("{}:{} 真实股价信息:最高价={},最低价={},开盘价={},收盘价={},今日命中={},预测明日:最高价={},最低价={},",
            //    code, stockDayData.getDate(),
            //    stockDayData.getMaxPrice(), stockDayData.getMinPrice(), stockDayData.getOpenPrice(),
            //    stockDayData.getClosePrice(), JSON.toJSONString(checkInfo),
            //    predictionData.getMaxPrice(), predictionData.getMinPrice()
            //);
        }
        StockPredictionStatistics statistics = doPredictionStatistics(stockDayDataList);
        //log.info("{} 预测总次数:{},命中最高价次数:{},命中最低价次数:{},全命中次数:{},等于卖出价次数:{},等于买入价次数:{},全等于次数:{}",
        //    code, stockDayDataList.size(),
        //    statistics.getMatchSellCount(), statistics.getMatchBuyCount(), statistics.getMatchAllCount(),
        //    statistics.getEqSellCount(), statistics.getEqBuyCount(), statistics.getEqAllCount());
        StockDayData lastData = stockDayDataList.get(stockDayDataList.size() - 1);
        lastData.setTomorrowPrediction(predictionData);
        lastData.setCheckInfo(checkInfo);
        return stockDayDataList;

    }

    public static StockPredictionStatistics doPredictionStatistics(List<StockDayData> stockDayDataList) {
        if (CollectionUtils.isEmpty(stockDayDataList)) {
            return null;
        }
        int matchSellCount = 0;
        int matchBuyCount = 0;
        int matchAllCount = 0;
        int eqSellCount = 0;
        int eqBuyCount = 0;
        int eqAllCount = 0;
        for (StockDayData stockDayData : stockDayDataList) {
            StockPredictionData predictionData = stockDayData.getTodayPrediction();
            //第一天不预测，直接跳过
            if (Objects.isNull(predictionData)) {
                continue;
            }
            StockPredictionCheckInfo checkInfo = stockDayData.getCheckInfo();
            if (Objects.isNull(checkInfo)) {
                continue;
            }
            if (checkInfo.isMatchSell()) {
                matchSellCount++;
            }
            if (checkInfo.isMatchBuy()) {
                matchBuyCount++;
            }
            if (checkInfo.isMatchAll()) {
                matchAllCount++;
            }
            if (checkInfo.isEqSell()) {
                eqSellCount++;
            }
            if (checkInfo.isEqBuy()) {
                eqBuyCount++;
            }
            if (checkInfo.isEqAll()) {
                eqAllCount++;
            }
        }
        StockDayData stockDayData = stockDayDataList.get(0);
        StockPredictionStatistics statistics = new StockPredictionStatistics();
        statistics.setCode(statistics.getCode());
        statistics.setYear(DateUtil.format(DateUtil.parseDate(stockDayData.getDate()), "yyyy"));
        statistics.setMatchAllCount(matchAllCount);
        statistics.setMatchSellCount(matchSellCount);
        statistics.setMatchBuyCount(matchBuyCount);
        statistics.setEqAllCount(eqAllCount);
        statistics.setEqSellCount(eqSellCount);
        statistics.setEqBuyCount(eqBuyCount);
        return statistics;
    }



    public static StockPredictionParam getDefaultPredictionParam() {
        StockPredictionParam param = new StockPredictionParam();
        param.setStrategyName("defaultPredictionStrategy");
        param.setMaxTotalHighDivideNum(new BigDecimal("7.94"));
        param.setMaxTotalLowDivideNum(new BigDecimal("8"));
        param.setMaxRangeFirstThreshold(new BigDecimal("0.03"));
        param.setMaxRangeSecondThreshold(new BigDecimal("0.05"));
        param.setMaxRangeRate(new BigDecimal("1.5"));
        param.setMaxRangeFirstRate(new BigDecimal("1.7"));
        param.setMaxRangeSecondRate(new BigDecimal("2.2"));
        param.setMinTotalHighDivideNum(new BigDecimal("7.93"));
        param.setMinTotalLowDivideNum(new BigDecimal("8"));
        param.setMinRangeFirstThreshold(new BigDecimal("0.03"));
        param.setMinRangeSecondThreshold(new BigDecimal("0.05"));
        param.setMinRangeRate(new BigDecimal("1"));
        param.setMinRangeFirstRate(new BigDecimal("1.5"));
        param.setMinRangeSecondRate(new BigDecimal("1.9"));
        return param;
    }

    /**
     * 未成交时补偿卖出价
     *
     * @param stockDayData
     * @param historyMinuteData
     * @return
     */
    private static BigDecimal getCompensateSellPrice(StockDayData stockDayData,
        List<StockMinuteData> historyMinuteData) {
        //if (CollectionUtils.isEmpty(historyMinuteData)) {
        //    return stockDayData.getClosePrice();
        //}
        //
        //String date = stockDayData.getDate();
        //for (StockMinuteData minuteData : historyMinuteData) {
        //    if (minuteData.getDate().equals(date) && minuteData.getMinute().equals("14:30:00")) {
        //        //14:30的价格比开盘价低，说明趋势下跌，用14:30的价格去卖
        //        if(stockDayData.getOpenPrice().compareTo(minuteData.getPrice())>0) {
        //            return minuteData.getPrice();
        //        }
        //    }
        //}
        return stockDayData.getClosePrice();
    }

    /**
     * 未成交时补偿买入价
     *
     * @param stockDayData
     * @param historyMinuteData
     * @return
     */
    private static BigDecimal getCompensateBuyPrice(StockDayData stockDayData,
        List<StockMinuteData> historyMinuteData) {
        //if (CollectionUtils.isEmpty(historyMinuteData)) {
        //    return stockDayData.getClosePrice();
        //}
        //boolean upFlag = stockDayData.getOpenPrice().compareTo(stockDayData.getClosePrice()) <= 0;
        //if (!upFlag) {
        //    return stockDayData.getClosePrice();
        //}
        //String date = stockDayData.getDate();
        //for (StockMinuteData minuteData : historyMinuteData) {
        //    if (minuteData.getDate().equals(date)
        //        && (minuteData.getMinute().equals("14:30:00"))) {
        //        //14:30的价格比开盘价高，说明趋势上涨，用14:30的价格去买,否则用尾盘价买
        //        if(stockDayData.getOpenPrice().compareTo(minuteData.getPrice())<=0) {
        //            return minuteData.getPrice();
        //        }
        //    }
        //}
        return stockDayData.getClosePrice();
    }

    /**
     * 出售库存股票
     *
     * @param buyPriceList
     * @param sellPrice
     */
    private static BigDecimal sellStoreStock(String date, List<BigDecimal> buyPriceList, BigDecimal sellPrice) {
        BigDecimal sy = new BigDecimal(0);
        for (BigDecimal buyPrice : buyPriceList) {
            sy = sy.add(sellPrice).subtract(buyPrice);
        }
        log.info("{} 出售库存股票,真实出售价:{},真实买入价:{},收益:{}", date, sellPrice,
            buyPriceList, sy);
        return sy;
    }

}
